Vue.component('context', {
	template: `
		<div class="menus">
			<div class="menu" v-for="(item, i) in menus" :key="item.name"
					@click.stop="handleMenuClick(item)">
				{{item.title}}
			</div>
		</div>
	`,
	data: function(){
		return {
			menus: [
				{title:'add craw data', name:"addCrawlerData"},
				{title: 'exit crawler', name:"exitCrawler"},
			]
		};
	},

	methods: {
		handelDrag: function(type, event){
			console.log(event);

		},

		handleMenuClick: function(menuInfo){
			let self = this;
			self.$bus.$emit('dispatch-event', {type: 'click', data: menuInfo});

		}
	
	},
	
});

const vueApp = new Vue({
	el: '#app',

	methods: {

	},
	
	beforeCreate: function(){
		Vue.prototype.$bus = this;

	},

	mounted: function(){
		let self = this;
		window.addEventListener('contextmenu', function(e){e.preventDefault(), e.stopPropagation()}, true);
		self.$bus.$on('dispatch-event', function(evtMsg){
			winPortKeeper.sendMessage({type: 'event', data: {name: 'menuClick', data: evtMsg}});
		});

	}


});

const utils = {
	ifNullAsVal: function(src, prop, useVal){
		if(null == src || null == src[prop]){
			return useVal;
		}
		return src[prop];

	},

	notEmpty: function(val){
		return null != val && '' != val;

	}

};

const state = {snapshot:{}};
const actions = {

	sendMessage: function(msgInfo) {
		let self = this;
		winPortKeeper.sendMessage(msgInfo);
	
	},

	sendUpdateSnapshotMsg: function(){
		let self = this;
		let msg = {type: 'cmd', data: {name: 'buildNodesSnapshot'}};
		winPortKeeper.sendMessage(msg);

	},

	buildSnapshot: function(snapshot){
		let snapshotMap = {};
		for(let key in snapshot){
			let node = snapshot[key];
			let nodeRef = snapshotMap[node.id];
			let tmpNode = {
				id: node.id,
				pid: node.pid,
				psid: node.psid,
				nsid: node.nsid,
				childOpen: false,
				type: utils.ifNullAsVal(node, 'nodeType', 0),
				name: utils.ifNullAsVal(node, 'nodeName', 'EMPTY'),
				value: utils.ifNullAsVal(node, 'nodeValue', ''),
				childNodes: [],
				childMap: {}
			};
			if(null == nodeRef){
				snapshotMap[node.id] = tmpNode;
			}
		}
		return snapshotMap;
		console.log('finish refresh snapshot map: ' + Object.keys(snapshotMap).length);
	
	},

	buildSnapshotTree: function(snapshot){
		let root = {
			id: 0,
			name: 'ROOT',
			childOpen: true,
			childNodes: [],
			childMap: {}
		};
		for(let key in snapshot){
			let nodeRef = snapshot[key];
			let parentRef = null == snapshot[nodeRef.pid] ? root : snapshot[nodeRef.pid];
			if(null == parentRef.childMap[nodeRef.id]){
				let appended = false;
				let siblingNodes = parentRef.childNodes;
				for(let i = 0; i < siblingNodes.length; i++){
					let siblingNode = siblingNodes[i];
					if(0 != nodeRef.psid && nodeRef.psid == siblingNode.id){
						siblingNodes.splice((i + 1), 0, nodeRef);
						appended = true;
						break;
					}
					if(0 != nodeRef.nsid && nodeRef.nsid == siblingNode.id){
						siblingNodes.splice(i, 0, nodeRef);
						appended = true;
						break;
					}
				}
				if(!appended){
					siblingNodes.push(nodeRef);
				}
			}
		}
		return root;

	},

	executeSnapshotUpdate: function(msgInfo){
		let self = this;
		let snapshot = self.buildSnapshot(msgInfo.data.data);
		let snapshotRoot = self.buildSnapshotTree(snapshot);
		vueApp.emit({name: 'update-tree', data: {root: snapshotRoot, snapshot: snapshot}});
		state.snapshot = snapshot;

	},

	executeDeltaSnapshotUpdate: function(msgInfo){
		let self = this;
		let updates = msgInfo.data.data;
		let nodeUpdates = null == updates || null == updates.nodeUpdates ? {} : updates.nodeUpdates;
		if(null != nodeUpdates.added || null != nodeUpdates.removed){
			let deltaUpdateMap = self.doNodesSnapshotUpdate(nodeUpdates);
			vueApp.emit({name: 'delta-update-tree', data: deltaUpdateMap});
			state.snapshot = deltaUpdateMap.snapshot;

		}

	},

	doNodesSnapshotUpdate: function(nodeUpdates){
		let self = this;
		let snapshot = state.snapshot;
		let addedDeltas = nodeUpdates.added;
		let removedDeltas = nodeUpdates.removed;
		let deltaUpdateMap = {};
		if(null != removedDeltas && Object.keys(removedDeltas).length > 0){
			let deltaSnapshot = self.buildSnapshot(removedDeltas);
			let deltaSnapshotRoot = self.buildSnapshotTree(deltaSnapshot);
			for(let key in deltaSnapshot){
				snapshot[key] = deltaSnapshot[key];
			}
			deltaUpdateMap.removed = deltaSnapshotRoot;
		}		
		if(null != addedDeltas && Object.keys(addedDeltas).length > 0){
			let deltaSnapshot = self.buildSnapshot(addedDeltas);
			let deltaSnapshotRoot = self.buildSnapshotTree(deltaSnapshot);
			for(let key in deltaSnapshot){
				if(null != snapshot[key]){
					delete snapshot[key];
				}
			}
			deltaUpdateMap.added = deltaSnapshotRoot;
		}
		deltaUpdateMap.snapshot = snapshot;
		return deltaUpdateMap;

	}

};

const winPortKeeper = {
	selfPort: null,
	parentPort: null,
	startKeeper: function(){
		let self = this;
		self.selfPort = window;
		self.selfPort.addEventListener('message', function(msgEvt){self.handleWinPortMsg(msgEvt)}, true);
		self.parentPort = window.parent;

	},

	handleWinPortMsg: function(msgEvt){
		let self = this;
		//console.log('receive content message');
		//console.log(msgEvt);
		let msg = msgEvt.data;
		if(null == msg || null == msg.from || 'content' != msg.from){
			return;
		}
		let type = msg.type;
		let name = msg.data.name;
		let from = msg.data.from;
		if('cmd' == type || 'cmd-resp' == type){
			if('updateSnapshot' == name || 'buildNodesSnapshot' == name){
				actions.executeSnapshotUpdate(msg);
				return;
			}
			if('deltaUpdateSnapshot' == name){
				actions.executeDeltaSnapshotUpdate(msg);
				return;
			}
			return;
		}

	},

	mid: 0,
	mCounter: 0,
	sendMessage: function(msgInfo){
		//console.log('send message to content');
		//console.log(msgInfo);
		let self = this;
		if(0 == self.mid){
			self.mid = new Date().getTime();
		}
		self.mCounter = self.mCounter + 1;
		msgInfo.sid = 'context:' + self.mid + self.mCounter;
		msgInfo.from = 'context';
		self.parentPort.postMessage(msgInfo, '*');

	},

};

winPortKeeper.startKeeper();
winPortKeeper.sendMessage({type: 'event', data:{name: 'ready'}});
actions.sendUpdateSnapshotMsg();